"""ConfigManager类 - 负责管理RPA框架的配置"""

import os
import json
import yaml
import logging
from typing import Dict, Any, Optional, Union
from pathlib import Path

from rpa_framework.rpa_logging.logger import Logger
from rpa_framework.exceptions.rpa_exceptions import ConfigException, FileNotFoundException

class ConfigManager:
    """配置管理器，负责加载、验证和提供配置访问"""
    
    # 默认配置
    DEFAULT_CONFIG = {
        'robot': {
            'name': 'DefaultRobot',
            'description': 'RPA Robot',
            'version': '1.0.0',
            'max_retries': 3,
            'retry_delay_seconds': 5,
            'timeout_seconds': 300,
            'headless_mode': False,
            'debug_mode': False
        },
        'logging': {
            'level': 'INFO',
            'file': 'robot.log',
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            'max_file_size': 10485760,  # 10MB
            'backup_count': 5
        },
        'browser': {
            'type': 'chrome',  # chrome, firefox, edge
            'timeout': 30,
            'implicit_wait': 10,
            'download_directory': './downloads',
            'user_agent': None,
            'extensions': [],
            'options': {},
            'driver_directory': None  # 默认使用系统路径，可设置为特定目录
        },
        'desktop': {
            'screenshot_directory': './screenshots',
            'image_recognition_threshold': 0.85,
            'click_duration': 0.1,
            'double_click_duration': 0.3,
            'drag_duration': 0.5,
            'typing_speed': 0.05  # 每次按键延迟50ms
        },
        'database': {
            'type': 'sqlite',
            'connection_string': 'sqlite:///robot.db',
            'timeout': 30
        },
        'environment': {
            'variables': {},
            'paths': {}
        },
        'security': {
            'encrypt_sensitive_data': True,
            'key_file': './config/encryption.key',
            'allowed_applications': []
        }
    }
    
    def __init__(self, config_file: Optional[str] = None):
        """初始化配置管理器
        
        Args:
            config_file: 配置文件路径（可选）
        """
        self.logger = Logger("ConfigManager")
        self._config = self.DEFAULT_CONFIG.copy()
        self._config_file = config_file
        
        # 初始化时加载配置
        if config_file:
            self.load_config(config_file)
        else:
            self.logger.info("使用默认配置")
        
        # 确保必要的目录存在
        self._ensure_directories()
    
    def _ensure_directories(self):
        """确保配置中指定的目录存在"""
        try:
            # 确保日志目录存在
            log_file = self.get('logging.file')
            if log_file:
                log_dir = os.path.dirname(log_file)
                if log_dir:
                    os.makedirs(log_dir, exist_ok=True)
            
            # 确保下载目录存在
            download_dir = self.get('browser.download_directory')
            if download_dir:
                os.makedirs(download_dir, exist_ok=True)
            
            # 确保截图目录存在
            screenshot_dir = self.get('desktop.screenshot_directory')
            if screenshot_dir:
                os.makedirs(screenshot_dir, exist_ok=True)
            
            # 确保配置目录存在
            key_file = self.get('security.key_file')
            if key_file:
                key_dir = os.path.dirname(key_file)
                if key_dir:
                    os.makedirs(key_dir, exist_ok=True)
        except Exception as e:
            self.logger.error(f"创建目录失败: {str(e)}")
    
    def load_config(self, config_file: str) -> None:
        """从文件加载配置
        
        Args:
            config_file: 配置文件路径
            
        Raises:
            FileNotFoundException: 配置文件不存在
            ConfigException: 配置文件格式错误或解析失败
        """
        self.logger.info(f"加载配置文件: {config_file}")
        
        if not os.path.exists(config_file):
            raise FileNotFoundException(f"配置文件不存在: {config_file}")
        
        try:
            file_extension = Path(config_file).suffix.lower()
            
            with open(config_file, 'r', encoding='utf-8') as f:
                if file_extension == '.json':
                    user_config = json.load(f)
                elif file_extension in ['.yaml', '.yml']:
                    user_config = yaml.safe_load(f)
                else:
                    raise ConfigException(f"不支持的配置文件格式: {file_extension}")
            
            # 合并配置（深度合并）
            self._merge_config(self._config, user_config)
            self.logger.info("配置加载成功")
            
            # 更新配置文件路径
            self._config_file = config_file
            
            # 确保必要的目录存在
            self._ensure_directories()
            
        except (json.JSONDecodeError, yaml.YAMLError) as e:
            raise ConfigException(f"配置文件解析失败: {str(e)}") from e
        except Exception as e:
            raise ConfigException(f"加载配置失败: {str(e)}") from e
    
    def _merge_config(self, base: Dict[str, Any], update: Dict[str, Any]) -> None:
        """深度合并配置字典
        
        Args:
            base: 基础配置字典
            update: 要合并的配置字典
        """
        for key, value in update.items():
            if key in base and isinstance(base[key], dict) and isinstance(value, dict):
                # 递归合并字典
                self._merge_config(base[key], value)
            else:
                # 替换或添加配置项
                base[key] = value
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值，支持点表示法
        
        Args:
            key: 配置键（支持点表示法，如 'robot.name'）
            default: 默认值
            
        Returns:
            配置值或默认值
        """
        keys = key.split('.')
        value = self._config
        
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            # 如果键不存在，返回默认值
            return default
    
    def set(self, key: str, value: Any) -> None:
        """设置配置值，支持点表示法
        
        Args:
            key: 配置键（支持点表示法，如 'robot.name'）
            value: 配置值
        """
        keys = key.split('.')
        config = self._config
        
        # 遍历到最后一个键的父级
        for k in keys[:-1]:
            if k not in config or not isinstance(config[k], dict):
                config[k] = {}
            config = config[k]
        
        # 设置最后一个键的值
        config[keys[-1]] = value
        self.logger.debug(f"配置项 '{key}' 已更新")
    
    def remove(self, key: str) -> bool:
        """移除配置项，支持点表示法
        
        Args:
            key: 配置键（支持点表示法，如 'robot.name'）
            
        Returns:
            是否成功移除
        """
        keys = key.split('.')
        config = self._config
        parent_configs = []
        parent_keys = []
        
        try:
            # 遍历到最后一个键
            for i, k in enumerate(keys):
                parent_configs.append(config)
                parent_keys.append(k)
                if i < len(keys) - 1:
                    config = config[k]
            
            # 移除配置项
            if keys[-1] in parent_configs[-1]:
                del parent_configs[-1][keys[-1]]
                self.logger.debug(f"配置项 '{key}' 已移除")
                
                # 清理空字典
                for i in range(len(parent_configs) - 2, -1, -1):
                    if not parent_configs[i + 1]:
                        del parent_configs[i][parent_keys[i + 1]]
                
                return True
            return False
        except (KeyError, TypeError):
            return False
    
    def has(self, key: str) -> bool:
        """检查配置项是否存在
        
        Args:
            key: 配置键（支持点表示法，如 'robot.name'）
            
        Returns:
            配置项是否存在
        """
        keys = key.split('.')
        value = self._config
        
        try:
            for k in keys:
                value = value[k]
            return True
        except (KeyError, TypeError):
            return False
    
    def get_all(self) -> Dict[str, Any]:
        """获取所有配置
        
        Returns:
            完整的配置字典
        """
        return self._config.copy()
    
    def update(self, config_dict: Dict[str, Any]) -> None:
        """使用字典更新配置
        
        Args:
            config_dict: 配置字典
        """
        self._merge_config(self._config, config_dict)
        self.logger.info("配置已更新")
        self._ensure_directories()
    
    def reset(self) -> None:
        """重置配置为默认值"""
        self._config = self.DEFAULT_CONFIG.copy()
        self.logger.info("配置已重置为默认值")
        self._ensure_directories()
    
    def reset_to_default(self) -> None:
        """重置配置为默认值（与reset方法功能相同，为兼容性提供）"""
        self.reset()
    
    def save_config(self, output_file: Optional[str] = None) -> None:
        """保存配置到文件
        
        Args:
            output_file: 输出文件路径（默认为加载的配置文件路径）
            
        Raises:
            ConfigException: 保存配置失败
        """
        file_path = output_file or self._config_file
        
        if not file_path:
            raise ConfigException("未指定输出文件路径")
        
        self.logger.info(f"保存配置到文件: {file_path}")
        
        try:
            file_extension = Path(file_path).suffix.lower()
            
            # 确保目录存在
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            
            with open(file_path, 'w', encoding='utf-8') as f:
                if file_extension == '.json':
                    json.dump(self._config, f, indent=2, ensure_ascii=False)
                elif file_extension in ['.yaml', '.yml']:
                    yaml.dump(self._config, f, default_flow_style=False, allow_unicode=True)
                else:
                    raise ConfigException(f"不支持的配置文件格式: {file_extension}")
            
            self.logger.info("配置保存成功")
        except Exception as e:
            raise ConfigException(f"保存配置失败: {str(e)}") from e
    
    def get_logging_config(self) -> Dict[str, Any]:
        """获取日志配置
        
        Returns:
            日志配置字典
        """
        return {
            'level': getattr(logging, self.get('logging.level', 'INFO')),
            'file': self.get('logging.file', 'robot.log'),
            'format': self.get('logging.format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s'),
            'max_file_size': self.get('logging.max_file_size', 10485760),
            'backup_count': self.get('logging.backup_count', 5)
        }
    
    def get_browser_config(self) -> Dict[str, Any]:
        """获取浏览器配置
        
        Returns:
            浏览器配置字典
        """
        return {
            'type': self.get('browser.type', 'chrome'),
            'timeout': self.get('browser.timeout', 30),
            'implicit_wait': self.get('browser.implicit_wait', 10),
            'download_directory': self.get('browser.download_directory', './downloads'),
            'user_agent': self.get('browser.user_agent'),
            'extensions': self.get('browser.extensions', []),
            'options': self.get('browser.options', {})
        }
    
    def get_robot_config(self) -> Dict[str, Any]:
        """获取机器人配置
        
        Returns:
            机器人配置字典
        """
        return {
            'name': self.get('robot.name', 'DefaultRobot'),
            'description': self.get('robot.description', 'RPA Robot'),
            'version': self.get('robot.version', '1.0.0'),
            'max_retries': self.get('robot.max_retries', 3),
            'retry_delay_seconds': self.get('robot.retry_delay_seconds', 5),
            'timeout_seconds': self.get('robot.timeout_seconds', 300),
            'headless_mode': self.get('robot.headless_mode', False),
            'debug_mode': self.get('robot.debug_mode', False)
        }
    
    def get_desktop_config(self) -> Dict[str, Any]:
        """获取桌面自动化配置
        
        Returns:
            桌面自动化配置字典
        """
        return {
            'screenshot_directory': self.get('desktop.screenshot_directory', './screenshots'),
            'image_recognition_threshold': self.get('desktop.image_recognition_threshold', 0.85),
            'click_duration': self.get('desktop.click_duration', 0.1),
            'double_click_duration': self.get('desktop.double_click_duration', 0.3),
            'drag_duration': self.get('desktop.drag_duration', 0.5),
            'typing_speed': self.get('desktop.typing_speed', 0.05)
        }
    
    def validate_config(self) -> Dict[str, str]:
        """验证配置的有效性
        
        Returns:
            错误信息字典 {配置键: 错误信息}
        """
        errors = {}
        
        # 验证机器人配置
        robot_config = self.get_robot_config()
        if robot_config['max_retries'] < 0:
            errors['robot.max_retries'] = '最大重试次数不能为负数'
        if robot_config['retry_delay_seconds'] < 0:
            errors['robot.retry_delay_seconds'] = '重试延迟不能为负数'
        if robot_config['timeout_seconds'] <= 0:
            errors['robot.timeout_seconds'] = '超时时间必须大于0'
        
        # 验证日志配置
        log_level = self.get('logging.level')
        valid_levels = ['DEBUG', 'INFO', 'WARNING', 'WARN', 'ERROR', 'CRITICAL']
        if log_level and log_level.upper() not in valid_levels:
            errors['logging.level'] = f'无效的日志级别，必须是以下之一: {", ".join(valid_levels)}'
        
        # 验证浏览器配置
        browser_type = self.get('browser.type')
        valid_browsers = ['chrome', 'firefox', 'edge']
        if browser_type and browser_type not in valid_browsers:
            errors['browser.type'] = f'无效的浏览器类型，必须是以下之一: {", ".join(valid_browsers)}'
        
        if self.get('browser.timeout', 30) <= 0:
            errors['browser.timeout'] = '浏览器超时必须大于0'
        
        # 验证桌面配置
        threshold = self.get('desktop.image_recognition_threshold', 0.85)
        if not (0 <= threshold <= 1):
            errors['desktop.image_recognition_threshold'] = '图像识别阈值必须在0到1之间'
        
        # 验证数据库配置
        db_type = self.get('database.type')
        if not db_type:
            errors['database.type'] = '数据库类型不能为空'
        
        return errors

# 创建全局配置管理器实例
config_manager = None

def get_config() -> ConfigManager:
    """获取全局配置管理器实例
    
    Returns:
        ConfigManager实例
    """
    global config_manager
    if config_manager is None:
        config_manager = ConfigManager()
    return config_manager

if __name__ == "__main__":
    # 示例用法
    try:
        # 创建配置管理器
        config = ConfigManager()
        
        # 获取配置值
        robot_name = config.get('robot.name')
        log_level = config.get('logging.level')
        
        print(f"默认机器人名称: {robot_name}")
        print(f"默认日志级别: {log_level}")
        
        # 修改配置
        config.set('robot.name', 'TestRobot')
        config.set('logging.level', 'DEBUG')
        
        print(f"修改后机器人名称: {config.get('robot.name')}")
        print(f"修改后日志级别: {config.get('logging.level')}")
        
        # 保存配置到临时文件
        config.save_config('test_config.json')
        print("配置已保存到 test_config.json")
        
        # 加载配置
        new_config = ConfigManager('test_config.json')
        print(f"从文件加载的机器人名称: {new_config.get('robot.name')}")
        
        # 验证配置
        errors = config.validate_config()
        if errors:
            print("配置验证错误:")
            for key, message in errors.items():
                print(f"  {key}: {message}")
        else:
            print("配置验证通过")
            
    except Exception as e:
        print(f"示例执行失败: {e}")